package com.freemalll.merchant.utils;

import lombok.extern.slf4j.Slf4j;

import java.lang.reflect.Field;
import java.math.BigDecimal;
import java.util.*;

/**
 * @author songshixiong
 * @ClassName DtoToMapUtil
 * @description:
 * @date 2025年05月13日
 * @version: 1.0
 */
@Slf4j
public class DtoToMapUtil {

    /**
     * 将 DTO 转换为 Map，并过滤掉 null 或空值字段
     */
    public static <T> Map<String, Object> convertToMap(T dto) {
        try {
            Map<String, Object> resultMap = new HashMap<>();
            if (dto == null) return resultMap;

            Field[] fields = dto.getClass().getDeclaredFields();
            for (Field field : fields) {
                field.setAccessible(true);
                String fieldName = field.getName();
                Object value = field.get(dto);
                //不为null并且不是MARK_DIFFERENCES字符串的值放入map
                if (isNotEmpty(value) && !"MARK_DIFFERENCES".equals(value)) {
                    resultMap.put(fieldName, value);
                }
            }
            return resultMap;
        } catch (SecurityException e) {
            log.error("SecurityException: ", e);
        } catch (IllegalArgumentException e) {
            log.error("IllegalArgumentException: ", e);
        } catch (IllegalAccessException e) {
            log.error("IllegalAccessException: ", e);
        }
        return new HashMap<>();
    }


    /**
     * 单个dto转换map 属性为空的属性也会在map中存在key
     *
     * @param dto
     * @param clazz
     * @param <T>
     * @return
     */
    public static <T> Map<String, Object> convertToMap(T dto, Class<T> clazz) {
        try {
            Map<String, Object> fieldMap = new HashMap<>();
            Field[] fields = clazz.getDeclaredFields();

            for (Field field : fields) {
                field.setAccessible(true);
                String fieldName = field.getName();
                Object value = field.get(dto);
                fieldMap.put(fieldName, value);
            }
            return fieldMap;
        } catch (IllegalAccessException e) {
            log.error("IllegalAccessException: ", e);
        }
        return new HashMap<>();
    }

    /**
     * 批量dto转换map 属性为空也会在map中存在key
     *
     * @param dtoList
     * @param clazz
     * @param <T>
     * @return
     */
    public static <T> List<Map<String, Object>> convertToListMap(List<T> dtoList, Class<T> clazz) {
        try {
            List<Map<String, Object>> mapList = new ArrayList<>();

            for (T dto : dtoList) {
                Map<String, Object> fieldMap = new HashMap<>();
                Field[] fields = clazz.getDeclaredFields();

                for (Field field : fields) {
                    field.setAccessible(true);
                    String fieldName = field.getName();
                    Object value = field.get(dto);
                    fieldMap.put(fieldName, value);
                }

                mapList.add(fieldMap);
            }

            return mapList;
        } catch (IllegalAccessException e) {
            log.error("IllegalAccessException: ", e);
        }
        return new ArrayList<>();
    }

    /**
     * 判断对象是否非空
     */
    private static boolean isNotEmpty(Object value) {
        if (value == null) {
            return false;
        }

        // 基础类型和包装类
        if (value instanceof String && ((String) value).trim().isEmpty()) {
            return false;
        }

        if (value instanceof Number && ((Number) value).doubleValue() == 0) {
            return false;
        }

        // BigDecimal 零值判断
        if (value instanceof BigDecimal && ((BigDecimal) value).compareTo(BigDecimal.ZERO) == 0) {
            return false;
        }

        // Boolean 类型不作空判断，只要不是 null 就保留
        if (value instanceof Boolean) {
            return true;
        }

        // 集合类型
        if (value instanceof Collection && ((Collection<?>) value).isEmpty()) {
            return false;
        }

        // Map 类型
        if (value instanceof Map && ((Map<?, ?>) value).isEmpty()) {
            return false;
        }

        // 数组类型
        if (value.getClass().isArray() && Arrays.asList((Object[]) value).isEmpty()) {
            return false;
        }

        return true;
    }
}
